package db

import (
	"fmt"
	"sync"
)

type KeyDir struct {
	rwmu    sync.RWMutex
	entries map[string]*entry
}

type KeyDirInterface interface {
	get(string) *entry
	del(string)
	put(string, *entry)
	updateFileID(_old uint32, _new uint32)
}

var once sync.Once
var keyDir *KeyDir

type entry struct {
	FileId      uint32
	ValueSize   uint32
	ValueOffset uint64
	TimeStamp   uint32
}

type entryInterface interface {
	toString() string
}

func NewKeyDir() *KeyDir {
	once.Do(func() {
		keyDir.entries = make(map[string]*entry)
	})
	return keyDir
}

func (k *KeyDir) get(key string) *entry {
	k.rwmu.RLocker()
	defer k.rwmu.RUnlock()
	return k.entries[key]
}

func (k *KeyDir) del(key string) {
	k.rwmu.Lock()
	defer k.rwmu.Unlock()
	delete(k.entries, key)
}

func (k *KeyDir) put(key string, value *entry) {
	k.rwmu.Lock()
	defer k.rwmu.Unlock()
	k.entries[key] = value
}

func (k *KeyDir) updateFileID(_old uint32, _new uint32) {
	k.rwmu.Lock()
	defer k.rwmu.Unlock()
	for _, v := range k.entries {
		if v.FileId == _old {
			v.FileId = _new
		}
	}
}

// key-dir's entry structure:
// key -> | file_id | value_sz | value_pos | tstamp |
func (e *entry) toString() string {
	return fmt.Sprintf("%d%d%d%d", e.FileId, e.ValueSize, e.ValueOffset, e.TimeStamp)
}
